package com.ecarx.module_udisk.controller;

import android.content.Context;
import android.os.SystemProperties;
import android.util.Log;

import com.ecarx.library_base.base_util.FileUtils;
import com.ecarx.library_base.usb.UDiskDevice;
import com.ecarx.library_base.usb.UDiskManager;
import com.ecarx.library_base.usb.brodcast.USBReceiver;
import com.ecarx.module_udisk.bean.LogBean;
import com.ecarx.module_udisk.bean.PathBean;
import com.ecarx.module_udisk.callback.FileUpdateCallback;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class FileUpdateController {
    private static final String TAG = FileUpdateController.class.getSimpleName();
    private static final String BASE_PATH = "/usb_upgrade/file_update/";
    private static final String PROPERTY_FILE_UPDATE_ENABLE = "persist.service.fileupdate.enable";
    private static final String PROPERTY_FILE_UPDATE_CHECK_ENABLE = "persist.service.fileupdate.check.enable";
    private static final String PROPERTY_FILE_UPDATE_EXIST = "ecarx.fileupdate.exist";
    private static final String PROPERTY_UDISK_FILE_PATH = "ecarx.fileupdate.udiskfilepath";
    private static final String PROPERTY_DEST_FILE_PATH = "ecarx.fileupdate.destfilepath";
    private static final String PROPERTY_DEST_PARENT_FILE_PATH = "ecarx.fileupdate.destparentfilepath";
    private static final String PROPERTY_FILE_UPDATE_SUCCESS = "ecarx.fileupdate.success";
    private static final String PROPERTY_FILE_UPDATE_FAIL_REASON = "ecarx.fileupdate.failreason";
    private static final String FILEUPDATE_FAILED = "0";
    private static final String FILEUPDATE_UPDATING = "2";
    private static final String FILEUPDATE_FILE_EXIST = "1";
    private static final String FILE_PATH_UXOS = "uxos";
    private static final int FILE_UPDATE_INTERVAL = 100;
    private static final int CHECK_PROPERTY_INTERVAL = 1000;
    private final Context mContext;
    private final FileUpdateCallback mFileUpdateCallback;
    private final SimpleDateFormat mFormatter = new SimpleDateFormat("HH:mm:ss.SSS");
    private List<LogBean> mLogList = new ArrayList<>();
    private String mCurrFilePath = "uxos";
    // 保存当前的U盘信息，用来处理在安装任务执行过程中U盘插拔的异常处理
    private UDiskDevice currentUDiskDevice;
    private Boolean installTaskExecute;

    public FileUpdateController(Context context, FileUpdateCallback fileUpdateCallback) {
        mContext = context;
        mFileUpdateCallback = fileUpdateCallback;
        dealDeviceInfo(UDiskManager.getInstance().getAllUDiskDevice());
        UDiskManager.getInstance().addUDiskChangeListener(new USBReceiver.UsbChangeCallback() {
            @Override
            public void onUsbDeviceChanged(boolean isAdd, List<UDiskDevice> uDiskDeviceList) {
                dealDeviceInfo(uDiskDeviceList);
            }
        });
    }

    private void dealDeviceInfo(List<UDiskDevice> mUDiskDeviceList) {
        if (!mUDiskDeviceList.isEmpty()) {
            UDiskDevice tempUDiskDevice = mUDiskDeviceList.get(0);
            if (currentUDiskDevice == null) {
                currentUDiskDevice = tempUDiskDevice;
            } else {
                String curUUID = currentUDiskDevice.getUuid();
                String callbackUUID = tempUDiskDevice.getUuid();
                if (curUUID != null && !curUUID.equals(callbackUUID)) {
                    Log.d(TAG, "installTaskExecute is false, uDisk changed");
                    installTaskExecute = false;
                    currentUDiskDevice = tempUDiskDevice;
                }
            }
            Log.d(TAG, "uDiskDevice info is: " + currentUDiskDevice.toString());
            mFileUpdateCallback.setUDiskInfo(currentUDiskDevice.getUSBName());
            analysisPathList(currentUDiskDevice.getPath());
        } else {
            mFileUpdateCallback.setUDiskInfo("");
            mFileUpdateCallback.setPathBeanList(null);
            Log.d(TAG, "installTaskExecute is false, uDisk missed");
            installTaskExecute = false;
        }
    }

    public void installPathList(List<String> filePathList) {
        if (filePathList == null || filePathList.size() == 0) {
            Log.d(TAG, "installPathList filePathList is null or 0 size");
            mFileUpdateCallback.fileUpdateLogEnd();
            return;
        }
        mLogList.add(new LogBean(stringWithTimeInfo(" file_update task start"), true));
        mFileUpdateCallback.fileUpdateLog(mLogList);
        SystemProperties.set(PROPERTY_UDISK_FILE_PATH, currentUDiskDevice.getInternalPath() + BASE_PATH + mCurrFilePath);
        for (String filePath : filePathList) {
            int index = filePath.indexOf(BASE_PATH + mCurrFilePath);
            if (index != -1) {
                String destFilePath = filePath.substring(index, filePath.length()).replace(BASE_PATH + mCurrFilePath, "");
                // uxos/clusteros/gameos各OS的文件升级统一入口，遍历列表按序升级
                doUpdateFile(destFilePath);
                boolean fail = FILEUPDATE_FAILED.equals(SystemProperties.get(PROPERTY_FILE_UPDATE_SUCCESS, ""));
                String result = destFilePath + " file_update ";
                if (fail) {
                    result += "failed:= " + SystemProperties.get(PROPERTY_FILE_UPDATE_FAIL_REASON, "");
                } else {
                    result += "success";
                }
                mLogList.add(new LogBean(stringWithTimeInfo(result), !fail));
                mFileUpdateCallback.fileUpdateLog(mLogList);
            }
        }
        mLogList.add(new LogBean(stringWithTimeInfo(" file_update task end"), true));
        mFileUpdateCallback.fileUpdateLog(mLogList);
        mFileUpdateCallback.fileUpdateLogEnd();
    }

    public void checkPathList(List<String> filePathList) {
        if (filePathList == null || filePathList.size() == 0) {
            Log.d(TAG, "filePathList is null or 0 size");
            mFileUpdateCallback.fileUpdateLogEnd();
            mFileUpdateCallback.pathListCheckFinish(true);
        }
        boolean result = true;
        mLogList.add(new LogBean(stringWithTimeInfo(" file_update check path validity start"), true));
        mFileUpdateCallback.fileUpdateLog(mLogList);
        for (String filePath : filePathList) {
            int index = filePath.indexOf(BASE_PATH + mCurrFilePath);
            if (index != -1) {
                String destFilePath = filePath.substring(index, filePath.length()).replace(BASE_PATH + mCurrFilePath, "");
                if (!checkUpdateFile(destFilePath)) {
                    mLogList.add(new LogBean(stringWithTimeInfo(" " + destFilePath + " path not valid"), false));
                    mFileUpdateCallback.fileUpdateLog(mLogList);
                    result = false;
                }
            }
        }
        mLogList.add(new LogBean(stringWithTimeInfo(" file_update check path validity end"), true));
        mFileUpdateCallback.fileUpdateLog(mLogList);
        mFileUpdateCallback.fileUpdateLogEnd();
        mFileUpdateCallback.pathListCheckFinish(result);
    }

    private boolean checkUpdateFile(String destFilePath) {
        try {
            SystemProperties.set(PROPERTY_FILE_UPDATE_CHECK_ENABLE, "0");
            SystemProperties.set(PROPERTY_DEST_FILE_PATH, destFilePath);
            SystemProperties.set(PROPERTY_FILE_UPDATE_CHECK_ENABLE, "1");
            Thread.sleep(FILE_UPDATE_INTERVAL);
            if (!FILEUPDATE_FILE_EXIST.equals(SystemProperties.get(PROPERTY_FILE_UPDATE_EXIST, ""))) {
                return false;
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    private String stringWithTimeInfo(String oldStr) {
        return mFormatter.format(new Date(System.currentTimeMillis())) + "  " + oldStr;
    }

    private void doUpdateFile(String destFilePath) {
        if (FILE_PATH_UXOS.equals(mCurrFilePath)) {
            copyFile(destFilePath);
        }
    }

    private void copyFile(String destFilePath) {
        try {
            String destParentFilePath = new File(destFilePath).getParentFile().toString();
            SystemProperties.set(PROPERTY_FILE_UPDATE_ENABLE, "0");
            SystemProperties.set(PROPERTY_DEST_FILE_PATH, destFilePath);
            SystemProperties.set(PROPERTY_DEST_PARENT_FILE_PATH, destParentFilePath);
            SystemProperties.set(PROPERTY_FILE_UPDATE_ENABLE, "1");
            Thread.sleep(FILE_UPDATE_INTERVAL);
            while (true) {
                if (!FILEUPDATE_UPDATING.equals(SystemProperties.get(PROPERTY_FILE_UPDATE_SUCCESS, ""))) {
                    break;
                }
                String result = destFilePath + " file_update upgrading";
                mLogList.add(new LogBean(stringWithTimeInfo(result), true));
                mFileUpdateCallback.fileUpdateLog(mLogList);
                Thread.sleep(CHECK_PROPERTY_INTERVAL);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void analysisPathList(String path) {
        List<String> pathList = FileUtils.getFilteredFilePathWithOutParent(path, BASE_PATH + mCurrFilePath, null);
        List<PathBean> pathBeanList = new ArrayList<>();
        for (String s : pathList) {
            PathBean bean = new PathBean(path + s, s.substring(BASE_PATH.length() + FILE_PATH_UXOS.length() + 1));
            pathBeanList.add(bean);
        }
        mFileUpdateCallback.setPathBeanList(pathBeanList);
    }
}